package controlador;

import java.awt.Color;
import java.awt.Desktop;
import java.awt.event.ActionEvent;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.EventObject;
import java.util.List;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JOptionPane;

import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRExporter;
import net.sf.jasperreports.engine.JRExporterParameter;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.engine.export.JRPdfExporter;
import net.sf.jasperreports.engine.util.JRLoader;

import org.pdfbox.examples.persistence.AppendDoc;
import org.pdfbox.exceptions.COSVisitorException;

import vista.frmImpresora;
import bean.Documento;
import bean.Reporte_Jasper;
/**
 * 
 * Clase que se encarga de gestionar todos los eventos sobre la vista
 * que permite la captura de opciones de impresion
 * 
 * @author Elam Torres
 * @version 1.0
 * @date 19/03/2012
 * 
 */
public class ControladorImpresora{
	private static ControladorImpresora controlador=null;
	private frmImpresora frmimpresora;
	private static List<Documento> documentos;
	/**
	 * Lista paralela a la lista de documentos 
	 * donde se alamacena un valor booleano
	 * que indicara si el documento sera impreso 
	 * o no
	 */
	private List<Boolean> documentos_imprimir;
	
	@SuppressWarnings("static-access")
	private ControladorImpresora(List<Documento> documentos) {
		super();
		this.frmimpresora = frmImpresora.getInstacia(this);
		this.frmimpresora.setLocationRelativeTo(null);
		this.frmimpresora.setVisible(true);
		this.frmimpresora.getPndatos().setBackground(new Color(239, 171, 183));
		this.frmimpresora.getPnmarco().setBackground(new Color(255, 219, 225));
		this.frmimpresora.setTitle("SACFE/Impresora de Documentos");
		this.documentos=documentos;
		this.documentos_imprimir = new ArrayList<Boolean>();
		for (int i=0;i<this.documentos.size();i++){
			documentos_imprimir.add(false);
		}
		cargarOpciones();
	}
	
	public static ControladorImpresora getInstacia(List<Documento> docs){
		if (controlador==null){
			controlador=new ControladorImpresora(docs);
		}else{
			documentos=docs;
		}
		controlador.getFrmimpresora().setVisible(true);
		controlador.getFrmimpresora().setState(JFrame.NORMAL);
		return controlador;
	}
	
	/**
	 * Metodo para cargar las opciones de impresion que se le mostraran al usuario
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	private void cargarOpciones() {
		List opciones = new ArrayList();
		for (int i=0;i<documentos.size();i++){
			opciones.add(documentos.get(i).getNombre());
		}
		getFrmimpresora().crearOpciones(opciones);
	}
	/**
	 * Metodo de comunicacion con la vista para gestionar
	 * los eventos que ocurran sobre ella
	 * @param e Evento enviado por la vista para ser gestionado
	 * @throws IOException 
	 * @throws COSVisitorException 
	 */
	public void procesarEvento(EventObject e){
		if (e.getSource().getClass().equals(JButton.class)){
			procesarEventoBoton(e);
		}else if(e.getSource().getClass().equals(JCheckBox.class)){
			procesarEventoCheckBox(e);
		}else if (e.getSource().getClass().getSuperclass().equals(JFrame.class)){
			procesarEventoJFrame(e);
		}
	}
	/**
	 * Metodo para procear eventos ocurridos sobre el frame de la impresora
	 * @param e evento generado por el usuario
	 */
	@SuppressWarnings("static-access")
	private void procesarEventoJFrame(EventObject e) {
		WindowEvent evento = (WindowEvent) e;
		if (evento.paramString().contains("WINDOW_CLOSING")){
			this.controlador=null;
		}
	}

	/**
	 * Metodo que procesa eventos generados sobre un objeto
	 * de tipo JButton
	 * @param e Evento de tipo EventObject que permitira determinar la accion a tomar
	 * @throws IOException 
	 * @throws COSVisitorException 
	 */
	private void procesarEventoBoton(EventObject e){
		if (e.getClass().equals(ActionEvent.class)){
			procesarClickBoton((ActionEvent)e);
		}
	}
	/**
	 * 
	 * @param e Evento de tipo ActionEvente que represente el click sobre un boton
	 * @throws IOException 
	 * @throws COSVisitorException 
	 */
	private void procesarClickBoton(ActionEvent e){
		if (e.getSource().equals(this.frmimpresora.getBtaceptar())){
			iniciarImpresion();
		}else if (e.getSource().equals(this.frmimpresora.getBtcancelar())){
			limpiarOpciones();
		}
	}

	private void cerrarImpresora() {
		this.controlador=null;
		getFrmimpresora().cerrarPantalla();
	}

	private void limpiarOpciones() {
		for (int i=0;i<this.frmimpresora.getOpciones().size();i++){
			((JCheckBox)this.frmimpresora.getOpciones().get(i)).setSelected(false);
			documentos_imprimir.set(i, false);
		}
	}

	/**
	 * Metodo que procesa eventos generados sobre un objeto
	 * de tipo CheckBox
	 * @param e Evento de tipo ActionEvent que permitira determinar la accion a tomar
	 */
	private void procesarEventoCheckBox(EventObject e) {
		if (e.getClass().equals(ActionEvent.class)){
			procesarClickCheckBox((ActionEvent)e);
		}
	}
	/**
	 * Metodo para procesar el click sobre un checkbox y determinar las acciones a
	 * tomar por el sistema
	 * @param e Evento de tipo ActionEvent que represente el click sobre checkbox
	 */
	private void procesarClickCheckBox(ActionEvent e) {
		String documento_seleccionado=e.getActionCommand();
		if (((JCheckBox)e.getSource()).isSelected()){
			cambiarEstadoDocumento(documento_seleccionado, true);
		}else{
			cambiarEstadoDocumento(documento_seleccionado, false);
		}
	}

	/**
	 * 
	 * @param nombre_documento nombre del documento al cual se le cambiara el estado de impresion
	 * @param estado estado de impresion que se le colocara al documento con el nombre indicado
	 */
	private void cambiarEstadoDocumento(String nombre_documento,boolean estado) {
		for (int i=0;i<documentos_imprimir.size();i++){
			if (documentos.get(i).getNombre().equals(nombre_documento)){
				documentos_imprimir.set(i, estado);
			}
		}
	}
	/**
	 * Metodo para Exporta los documentos bajo las opciones indicadas
	 * por el usuario en un forma imprimible
	 * @throws IOException 
	 * @throws COSVisitorException 
	 */
	private void iniciarImpresion(){
		if (sonValidasOpciones()){
			for (int i=0;i<documentos_imprimir.size();i++){
				if (documentos_imprimir.get(i)){
					imprimirDocumento(documentos.get(i));
				}
			}
			cerrarImpresora();
			JOptionPane.showMessageDialog(frmimpresora, "Documentos Exportados Exitosamente", "SACFRE/Impresora", JOptionPane.INFORMATION_MESSAGE);
			//Desktop.getDesktop().open(fucionarDocumentosPDF(documentos_impresos));
		}else{
			JOptionPane.showMessageDialog(frmimpresora, "Debe seleccionar al menos una opcion");
		}
	}
	@SuppressWarnings("unused")
	private File fucionarDocumentosPDF(List<Documento> documentos_impresos){
		String documento1,documento2,resultado="Reporte.pdf",directorio;
		if (hayMasDeUnDocumentoEn(documentos_impresos)){
			AppendDoc twin = new AppendDoc();
			directorio = documentos_impresos.get(0).getDirectorio();
			resultado=directorio.concat(resultado);
			try {
				for (int i=0;i<documentos_impresos.size();i++){
					if(i==0){
						documento1 = documentos_impresos.get(i).getDirectorio().concat(documentos_impresos.get(i).getNombre().concat(".pdf"));
						documento2 = documentos_impresos.get(i+1).getDirectorio().concat(documentos_impresos.get(i+1).getNombre().concat(".pdf"));
						twin.doIt(documento1, documento2, resultado);
						i++;
					}else{
						documento1 = documentos_impresos.get(i).getDirectorio().concat(documentos_impresos.get(i).getNombre().concat(".pdf"));
						twin.doIt(resultado, documento1, resultado);
					}
				}
			}catch (Exception e) {
				// TODO: handle exception
			}
		}
		return new File(resultado);
	}

	private boolean hayMasDeUnDocumentoEn(List<Documento> documentos_impresos) {
		return documentos_impresos.size()>1;
	}

	private void imprimirDocumento(Documento documento) {
		if (documento.getClass().getSuperclass().equals(Reporte_Jasper.class)){
			imprimirReporteJasper((Reporte_Jasper)documento);
		}
	}

	@SuppressWarnings("deprecation")
	private void imprimirReporteJasper(Reporte_Jasper documento){
		JasperReport reporte;
		try {
			System.out.println(documento.getDi_out());
			reporte = (JasperReport) JRLoader.loadObject(documento.getDir_jasper());
			JasperPrint jasperPrint = JasperFillManager.fillReport(reporte, documento.getParametros(), new JRBeanCollectionDataSource(documento.getJrbeancollention()));
	        JRExporter exporter = new JRPdfExporter(); 
	        exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
	        exporter.setParameter(JRExporterParameter.OUTPUT_FILE, new java.io.File(documento.getDi_out().replace(" ", ""))); 
	        exporter.exportReport();
        } catch (JRException e1) {
			e1.printStackTrace();
		}
	}

	private boolean sonValidasOpciones() {
		boolean estado=false;
		for (int i=0;i<documentos_imprimir.size();i++){
			if (documentos_imprimir.get(i)){
				estado |=true;
			}
		}
		return estado;
	}

	/**
	 * 
	 * @return La vista a la cual esta clase controla (Gestiona sus Eventos)
	 */
	public frmImpresora getFrmimpresora() {
		return frmimpresora;
	}
	@SuppressWarnings("rawtypes")
	public List getDocumentos() {
		return documentos;
	}
	@SuppressWarnings("rawtypes")
	public List getDocumentos_imprimir() {
		return documentos_imprimir;
	}
	
	
}
